from typing import Optional, Dict, Any, Union
from fastapi import Request
from sqlalchemy.orm import Session
from app.database.repository.user_repository import UserRepository
from app.exception.code_exception import CodeException
from app.models.models import User
from app.utils.jwt_utils import JWTUtils
from app.core.cons import Cons
import json

class RequestUtils:
    @staticmethod
    def get_token(request: Request) -> Optional[str]:
        # 首先尝试从参数中获取token
        token = request.query_params.get("token")
        
        # 如果路径参数中没有token，则尝试从header中获取Bearer token
        if not token:
            token = request.headers.get("token")

        if not token:
            auth_header = request.headers.get("Authorization")
            if auth_header and auth_header.startswith("Bearer "):
                token = auth_header[7:]  # 移除"Bearer "前缀
        return token

    @staticmethod
    def login_user(request: Request, db: Session) -> Optional[User]:
        # 首先尝试从参数中获取token
        token = RequestUtils.get_token(request)
        
        # 如果没有找到token，返回None
        if not token:
            return None
        
        # 验证token并获取用户ID
        user_id = JWTUtils.verify_token(token)
        if user_id is None:
            return None
        # 查找用户
        user = UserRepository(db).find_by_id(user_id)
        return user

    @staticmethod
    def login_user_and_check(request: Request, db: Session) -> Optional[User]:
        # 查找用户
        user = RequestUtils.login_user(request, db)
        if not user:
            raise CodeException.no_login()

        return user
        
    @staticmethod
    async def get_request_params(request: Request, truncate_length: int = 1000) -> Dict[str, Any]:
        """
        根据HTTP方法获取并处理请求参数
        
        Args:
            request: FastAPI请求对象
            truncate_length: 参数值截断长度
            
        Returns:
            Dict: 包含请求参数信息的字典
        """
        result = {}
        
        # 获取查询参数
        query_params = dict(request.query_params)
        if query_params:
            result['query_params'] = query_params
        
        # 仅在POST/PUT/PATCH/DELETE等方法中尝试获取请求体
        if request.method in ['POST', 'PUT', 'PATCH', 'DELETE']:
            request_body = None
            try:
                # 读取请求体
                body = await request.body()
                if body:
                    # 尝试解析为JSON
                    try:
                        request_body = json.loads(body.decode(Cons.UTF_8, errors='ignore'))
                    except:
                        # 如果不是JSON，则记录原始内容
                        request_body = body.decode(Cons.UTF_8, errors='ignore')
                    
                    # 处理敏感信息
                    if isinstance(request_body, dict):
                        if 'password' in request_body:
                            request_body['password'] = '****'
                        if 'token' in request_body:
                            request_body['token'] = '****'
                    
                    # 截断过长的请求体
                    if isinstance(request_body, (str, dict, list)):
                        body_str = json.dumps(request_body) if isinstance(request_body, (dict, list)) else request_body
                        if len(body_str) > truncate_length:
                            request_body = body_str[:truncate_length] + "... [truncated]"
                
                result['body'] = request_body
                result['raw_body'] = body
                
            except Exception as e:
                result['body'] = "[Failed to read]"
                result['error'] = str(e)
        
        return result
        
    @staticmethod
    def sanitize_headers(headers: Dict[str, str]) -> Dict[str, str]:
        """
        处理敏感头信息
        
        Args:
            headers: 请求头字典
            
        Returns:
            Dict: 处理后的请求头
        """
        sanitized = headers.copy()
        if "authorization" in sanitized:
            sanitized["authorization"] = "Bearer ****"
        if "cookie" in sanitized:
            sanitized["cookie"] = "****"
        return sanitized